package com.jdd.modules.parkcar.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.util.CacheUtil;
import com.jdd.common.util.DateUtils;
import com.jdd.modules.order.entity.ParkOrderInfo;
import com.jdd.modules.parkcar.entity.ParkCarOutAbnormalLog;
import com.jdd.modules.parkcar.mapper.ParkCarOutAbnormalLogMapper;
import com.jdd.modules.parkcar.service.IParkCarOutAbnormalLogService;
import com.jdd.modules.parking.entity.ParkArmInfo;
import com.jdd.modules.parking.entity.ParkCarEnterLog;
import com.jdd.modules.parking.mapper.ParkArmInfoMapper;
import com.jdd.modules.parking.mapper.ParkCarEnterLogMapper;
import com.jdd.modules.parking.vo.ParkCarEnterLogDTO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 车辆异常出场日志表
 * @Author: jdd
 * @Date: 2021-09-09
 * @Version: V1.0
 */
@Service
public class ParkCarOutAbnormalLogServiceImpl extends ServiceImpl<ParkCarOutAbnormalLogMapper, ParkCarOutAbnormalLog> implements IParkCarOutAbnormalLogService {

    @Resource
    private ParkArmInfoMapper parkArmInfoMapper;
    @Resource
    private ParkCarEnterLogMapper parkCarEnterLogMapper;
    @Resource
    private CacheUtil cacheUtil;

    /**
     * 查询近15天异常出场记录
     *
     * @return
     */
    @Override
    public List<ParkCarEnterLogDTO> findAbnormalLog() {
        //载体
        List<ParkCarEnterLogDTO> list = new ArrayList<>();
        //当前时间
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat nowFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //获取前面的时间用-负号
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DAY_OF_MONTH, -15);
        //15天之间的时间
        String before = nowFormat.format(cal.getTime());
        String now = nowFormat.format(date);
        //指定时间段内所有异常出场记录
        List<ParkCarEnterLogDTO> enterLogIds = this.findNoNormalEnterLogIds(before, now);
        //每天的,从前向后排序
        for (int i = 14; i >= 0; i--) {
            Calendar today = Calendar.getInstance();
            today.setTime(date);
            today.add(Calendar.DAY_OF_MONTH, -i);
            //过滤所有记录，封装成每天的
            List<ParkCarEnterLogDTO> collect = enterLogIds.stream().filter(item -> {
                boolean before_flag = false;
                boolean after_flag = false;
                try {
                    //入场时间属于当前时间段的
                    Date enterTime = nowFormat.parse(item.getTime());
                    //进场时间与当天的零点比
                    Date parse = nowFormat.parse(sdf.format(today.getTime()) + " 00:00:00");
                    after_flag = enterTime.after(parse);
                    //进场时间与当天的24点比
                    Date parse2 = nowFormat.parse(sdf.format(today.getTime()) + " 23:59:59");
                    before_flag = enterTime.before(parse2);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return before_flag && after_flag;
            }).collect(Collectors.toList());
            ParkCarEnterLogDTO parkCarEnterLogDTO = new ParkCarEnterLogDTO();
            //当天时间
            parkCarEnterLogDTO.setTime(sdf.format(today.getTime()));
            //当天数量
            parkCarEnterLogDTO.setAbnormalNumber(collect.size());
            list.add(parkCarEnterLogDTO);
        }
        return list;
    }

    /**
     * 判断异常记录并且保存,两个参数不能都为null
     *
     * @param carEnterLog 入场纪录，为null时是无入场手动开闸，不为null时判断补录或者匹配
     * @param orderInfo   订单信息，为null时是二次进场，异常记录表要用
     */
    @Override
    public void saveAbnormal(ParkCarEnterLog carEnterLog, ParkOrderInfo orderInfo) {
        try {
            //生成异常实体表
            ParkCarOutAbnormalLog parkCarOutAbnormalLog = new ParkCarOutAbnormalLog();
            //入场纪录id
            //如果这里出现空指针说明vo传过来的enterId非法
            String enterLogId = carEnterLog.getId();
            //如果入场和订单信息都为空说明传来的参数不正常
            //入场的id可能传来为空，但是订单信息一定有数据
            if (ObjectUtil.isNull(orderInfo) || ObjectUtil.isEmpty(orderInfo)) {
                if (ObjectUtil.isNull(carEnterLog) || ObjectUtil.isEmpty(carEnterLog)) {
                    throw new Exception("保存异常记录需要传参数！！！");
                } else {
                    //入口时判断
                    //二次进场条件2：有入场记录
                    BeanUtils.copyProperties(carEnterLog, parkCarOutAbnormalLog);
                    parkCarOutAbnormalLog.setCarEnterId(enterLogId);
                    parkCarOutAbnormalLog.setCreateTime(new Date());
                    //记录二次进场的异常
                    saveAbnormalByTypeMoney(parkCarOutAbnormalLog, JddConstant.AbnormalType.TWO_ENTER, JddConstant.StringNumber.STRING_ZERO);
                }
            } else {
                //异常都靠订单或者入场记录获取异常信息
                BeanUtils.copyProperties(orderInfo, parkCarOutAbnormalLog);
                parkCarOutAbnormalLog.setCarEnterId(enterLogId);
                parkCarOutAbnormalLog.setOrderId(orderInfo.getId());
                ParkArmInfo infoBySerialNo = parkArmInfoMapper.queryParkArmInfoBySerialNo(orderInfo.getSerialNo());
                parkCarOutAbnormalLog.setIpAddr(infoBySerialNo.getIpAddr());

                //无入场岗亭手动开闸异常条件1：有订单信息   2：无入场记录
                if (StringUtils.isBlank(enterLogId)) {
                    //判断是否免费
                    if (StringUtils.isNotBlank(orderInfo.getChargeTotalFee()) && !JddConstant.StringNumber.STRING_ZERO.equals(orderInfo.getChargeTotalFee())) {
                        //保存有费用岗亭人工开闸
                        parkCarOutAbnormalLog.setCreateTime(new Date());
                        saveAbnormalByTypeMoney(parkCarOutAbnormalLog, JddConstant.AbnormalType.NO_ENTER_HASFEE, orderInfo.getChargeTotalFee());
                        return;
                    }
                    //保存无费用岗亭人工开闸情况
                    //无入场的时候不保存订单信息，所以这里为空
                    parkCarOutAbnormalLog.setOrderId(null);
                    parkCarOutAbnormalLog.setCreateTime(new Date());
                    saveAbnormalByTypeMoney(parkCarOutAbnormalLog, JddConstant.AbnormalType.NO_ENTER_NOFEE, JddConstant.StringNumber.STRING_ZERO);
                    return;
                }

                //补录入场异常条件：1.有订单信息   2.有入场纪录，入场序列号与当前闸机序列号一致（都是出场序列号）
                if (carEnterLog.getSerialNo().equals(orderInfo.getSerialNo())) {
                    //这里直接更新异常
                    UpdateWrapper<ParkCarOutAbnormalLog> wrapper = new UpdateWrapper<>();
                    wrapper.set("pay_status", JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
                    wrapper.set("car_out_time", DateUtils.formatDateTime());
                    //有收费信息
                    if (StringUtils.isNotBlank(orderInfo.getChargeTotalFee()) && !JddConstant.StringNumber.STRING_ZERO.equals(orderInfo.getChargeTotalFee())) {
                        wrapper.set("remark", "线下支付");
                        wrapper.set("record_type", JddConstant.AbnormalType.ADD_ENTER_HASFEE);
                    } else {
                        wrapper.set("remark", "免费放行");
                        wrapper.set("record_type", JddConstant.AbnormalType.ADD_ENTER_NOFEE);
                    }
                    wrapper.eq("car_enter_id", carEnterLog.getId());
                    this.update(wrapper);
                    return;
                }
                //如果不是补录，不是无入场放行，剩下的下面这个就是匹配
                //拿到入场的
                String falsePlateNo = cacheUtil.get("truePlateNo", orderInfo.getPlateNo());
                parkCarOutAbnormalLog.setRemark("入口车牌号：" + falsePlateNo);
                //更改入场记录
                parkCarEnterLogMapper.changePlate(enterLogId, orderInfo.getPlateNo());
                //使用后删除缓存
                cacheUtil.delete("truePlateNo", orderInfo.getPlateNo());
                //有收费信息
                if (StringUtils.isNotBlank(orderInfo.getChargeTotalFee()) && !JddConstant.StringNumber.STRING_ZERO.equals(orderInfo.getChargeTotalFee())) {
                    parkCarOutAbnormalLog.setCreateTime(new Date());
                    saveAbnormalByTypeMoney(parkCarOutAbnormalLog, JddConstant.AbnormalType.LIKE_ENTER_HASFEE, orderInfo.getChargeTotalFee());
                    return;
                }
                parkCarOutAbnormalLog.setCreateTime(new Date());
                saveAbnormalByTypeMoney(parkCarOutAbnormalLog, JddConstant.AbnormalType.LIKE_ENTER_NOFEE, JddConstant.StringNumber.STRING_ZERO);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 功能描述: 判断异常类型并保存
     *
     * @param parkCarOutAbnormalLog 异常类实体
     * @param type                  异常类型
     * @param money                 收费金额
     * @Author: lcy
     * @Date: 2021/9/11
     */
    private void saveAbnormalByTypeMoney(ParkCarOutAbnormalLog parkCarOutAbnormalLog, String type, String money) {
        //换班的数据要有出场记录
        parkCarOutAbnormalLog.setCarOutTime(DateUtils.formatDateTime());
        //根据类型和金额设置不同值
        if (JddConstant.StringNumber.STRING_ZERO.equals(money)) {
            if (null != parkCarOutAbnormalLog.getRemark()) {
                parkCarOutAbnormalLog.setRemark(parkCarOutAbnormalLog.getRemark() + "，免费放行");
            } else {
                parkCarOutAbnormalLog.setRemark("免费放行");
            }
        } else {
            if (null != parkCarOutAbnormalLog.getRemark()) {
                parkCarOutAbnormalLog.setRemark(parkCarOutAbnormalLog.getRemark() + "，线下支付");
            } else {
                parkCarOutAbnormalLog.setRemark("线下支付");
            }
            parkCarOutAbnormalLog.setPayStatus(JddConstant.OrderConstant.ORDER_PAY_STATE_SUCCESS);
        }
        parkCarOutAbnormalLog.setRecordType(type);
        this.save(parkCarOutAbnormalLog);
    }

    /**
     * 查找二次进场的异常车辆，并保存到异常记录
     *
     * @param targetAreaId 目标区域id
     * @param license      车牌号
     */
    @Override
    public void findAbnormals(String targetAreaId, String license) {
        QueryWrapper<ParkCarEnterLog> wrapper = new QueryWrapper<>();
        wrapper.eq("plate_no", license);
        wrapper.eq("area_id", targetAreaId);
        wrapper.eq("is_out", JddConstant.StringNumber.STRING_ZERO);
        List<ParkCarEnterLog> list = parkCarEnterLogMapper.selectList(wrapper);
        //查到当前进大车场车辆，但是已经有入场纪录且没出场的记录，记录异常表
        if (null != list && list.size() != 0) {
            this.saveAbnormal(list.get(0), null);
        }
    }

    /**
     * 功能描述:查询指定时间的异常记录
     *
     * @param before 起始时间
     * @param now    结束时间
     * @Author: lcy
     * @Date: 2021/9/11
     */
    private List<ParkCarEnterLogDTO> findNoNormalEnterLogIds(String before, String now) {
        QueryWrapper<ParkCarOutAbnormalLog> wrapper = new QueryWrapper<>();
        wrapper.between("create_time", before, now);
        //该时间段的异常记录
        List<ParkCarOutAbnormalLog> list = this.list(wrapper);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //封装成前端显示的集合
        List<ParkCarEnterLogDTO> collect = list.stream().map(item -> {
            ParkCarEnterLogDTO parkCarEnterLogDTO = new ParkCarEnterLogDTO();
            parkCarEnterLogDTO.setTime(simpleDateFormat.format(item.getCreateTime()));
            return parkCarEnterLogDTO;
        }).collect(Collectors.toList());
        return collect;
    }
}
